package cn.xiaolang.thread.juc;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 多个线程相互等待，只有当多个线程都到达时，线程才会继续进行；
 * 典型的应用如并行计算，当某个处理的运算量很大时，可以将该运算任务拆分成多个子任务，
 * 等待所有的子任务都完成之后，父任务再拿到所有子任务的运算结果进行汇总。
 *
 * @author fuhw/Dean
 * @date 2020-03-17
 */
@Slf4j
public class CyclicBarrierStarted {

    /**
     * <p>示例输出：</p>
     * 17:27:29.977 [cyclic-worker-2] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.2 come
     * 17:27:29.976 [cyclic-worker-0] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.0 come
     * 17:27:29.976 [cyclic-worker-4] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.4 come
     * 17:27:29.976 [cyclic-worker-1] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.1 come
     * 17:27:29.976 [cyclic-worker-3] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.3 come
     * 17:27:29.981 [cyclic-worker-3] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - Everyone's here
     * 17:27:29.981 [cyclic-worker-3] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.3 leave
     * 17:27:29.981 [cyclic-worker-2] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.2 leave
     * 17:27:29.981 [cyclic-worker-4] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.4 leave
     * 17:27:29.981 [cyclic-worker-0] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.0 leave
     * 17:27:29.981 [cyclic-worker-1] INFO cn.xiaolang.thread.juc.CyclicBarrierStarted - No.1 leave
     */
    public static void main(String[] args) {
        final int totalThread = 5;
        List<Future<String>> clildrenResults = new ArrayList<>();
        List<Integer> calculateSubRes = new ArrayList<>();
        CyclicBarrier cyclicBarrier = new CyclicBarrier(totalThread, () -> {
            int sum = calculateSubRes.stream().mapToInt(Integer::intValue)
                    .sum();
            log.info("Everyone's here：{}={}",StringUtils.collectionToDelimitedString(calculateSubRes,"+"), sum);
        });
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("cyclic-worker-%d").build();
        ExecutorService executorService = Executors.newCachedThreadPool(factory);
        for (int i = 0; i < totalThread; i++) {
            final int count = i;
            Callable<String> callable = () -> {
                log.info("No.{} come", count);
                try {
                    // 表示自己已经到达栅栏
                    calculateSubRes.add(count+10);
                    cyclicBarrier.await();
                } catch (BrokenBarrierException | InterruptedException e) {
                    log.error("", e);
                    /* Clean up whatever needs to be handled before interrupting  */
                    Thread.currentThread().interrupt();
                }
                log.info("No.{} leave", count);
                // 执行任务
                return "No." + count;
            };
            Future<String> submit = executorService.submit(callable);
            clildrenResults.add(submit);
        }
        StringBuilder stringBuilder = new StringBuilder();
        clildrenResults.forEach(a -> {
            try {
                stringBuilder.append(a.get());
            } catch (Exception e) {
                log.error("", e);
                Thread.currentThread().interrupt();
            }
        });
       log.info("所有任务的执行结果：{}",stringBuilder);
        executorService.shutdown();
    }
}
